/*=============================================================================
*
*   Copyright (C) 2020 All rights reserved.
*
*   Filename:		nodal_dof.hpp
*
*   Author: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Date: 2020-03-04 17:39
*
*   Last Editors: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Last modified:	2020-03-19 13:10
*
*   Description:
*
=============================================================================*/
#ifndef ADD_NODAL_DOF_H
#define ADD_NODAL_DOF_H

#include "../../model/dof.hpp"

namespace geoxfem {
namespace geometry {

template <typename CouplePolicy>
struct set_nodal_dofs { /*{{{*/
  template <typename Vertex>
  static void apply(Vertex&) {
    throw "not implemented yet";
  }
}; /*}}}*/

template <typename CouplePolicy>
struct get_nodal_dofs { /*{{{*/
  template <typename Vertex>
  static std::vector<model::Dof*> apply(Vertex&) {
    throw "not implemented yet";
  }
}; /*}}}*/

}  // namespace geometry

namespace model {

template <typename CouplePolicy>
struct update_dirichlet_dof { /*{{{*/
  template <typename TimeStep>
  static void apply(const TimeStep& tstep, Dof& dof) {
    _real etime = tstep.getEndTime();
    if(dof.ifDirichlet())
      dof.setBoundaryValue(dof.getTimeFunction()->getValueAt(etime));
    return;
  }
  template <typename TimeStep>
  static void apply(const TimeStep& tstep, Dof* dof) {
    apply(tstep, *dof);
  }
}; /*}}}*/

template <typename CouplePolicy>
struct update_neumann_dof { /*{{{*/
  template <typename TimeStep>
  static void apply(const TimeStep& tstep, Dof& dof) {
    _real etime = tstep.getEndTime();
    if(dof.ifNeumann())
      dof.setBoundaryValue(dof.getTimeFunction()->getValueAt(etime));
    return;
  }
  template <typename TimeStep>
  static void apply(const TimeStep& tstep, Dof* dof) {
    apply(tstep, *dof);
  }
}; /*}}}*/

template <typename CouplePolicy>
struct update_nodal_boundary_condition { /*{{{*/
  template <typename Vertex, typename TimeStep>
  static void apply(const TimeStep& tstep, Vertex& vertex) {
    auto dof_list = geometry::get_nodal_dofs<CouplePolicy>::apply(vertex);
    for(auto dof : dof_list) {
      update_dirichlet_dof<CouplePolicy>::apply(tstep, *dof);
      update_neumann_dof<CouplePolicy>::apply(tstep, *dof);
    }
    return;
  }
}; /*}}}*/

}  // namespace model
}  // namespace geoxfem

#endif /* ADD_NODAL_DOF_H */
